package com.appspot.inkisapi.servlet;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.appspot.inkisapi.entity.BlogPost;
import com.appspot.inkisapi.service.BlogPostService;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gson.Gson;

public class SimpleBlogApiServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public static final String POSTS_KIND = "posts";

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException {
		String[] nouns = request.getRequestURI().split("/");
		if (nouns.length <= 2 || (nouns.length > 4)) {
			sendError(response, HttpServletResponse.SC_BAD_REQUEST,
					"URI length exceed limit");
			return;
		}
		String kind = nouns[2];
		if (!kind.equalsIgnoreCase(POSTS_KIND)) {
			sendError(response, HttpServletResponse.SC_BAD_REQUEST,
					"API is not supported");
			return;
		}

		String id = null;
		if (nouns.length == 4) {
			id = nouns[3];
		}

		// Work out what the HTTP action was
		String verb = request.getMethod();
		if (verb.equals("GET")) {
			handleGet(kind, id, request, response);
			return;
		} else if (verb.equals("POST")) {
			if (id != null) {
				sendError(response, HttpServletResponse.SC_BAD_REQUEST,
						"Bad request URI");
				return;
			}
			handlePost(kind, request, response);
			return;
		} else if (verb.equals("PUT")) {
			if (id == null) {
				sendError(response, HttpServletResponse.SC_BAD_REQUEST,
						"ID should be specified");
				return;
			}
			handlePut(kind, id, request, response);
			return;
		} else if (verb.equals("DELETE")) {
			if (id == null) {
				sendError(response, HttpServletResponse.SC_BAD_REQUEST,
						"ID should be specified");
				return;
			}
			handleDelete(kind, id, response);
			return;
		} else {
			sendError(response, HttpServletResponse.SC_METHOD_NOT_ALLOWED,
					"Request method is not supported");
			return;
		}
	}

	public void handleGet(String kind, String id, HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException {
		try {
			if (kind.equalsIgnoreCase(POSTS_KIND)) {
				if (id == null) { // get all item of kind
					String author = request.getParameter("author");
					List<BlogPost> results = null;
					if (author == null){
						results = BlogPostService.getAllBlogPosts();
					} else {
						results = BlogPostService.getBlogPostsWith("author", author);
					}
					if (results == null) {
						sendError(response,
								HttpServletResponse.SC_METHOD_NOT_ALLOWED,
								"Request items do not exist");
						return;
					}
					Gson gson = new Gson();
					String json = gson.toJson(results);
					response.setContentType("application/json; charset=utf-8");
					response.addHeader("Access-Control-Allow-Origin", "*");
					response.addHeader("Cache-Control",
							"max-age=0,no-cache,no-store,post-check=0,pre-check=0");
					response.addHeader("Expires",
							"Mon, 26 Jul 1997 05:00:00 GMT");
					response.setStatus(HttpServletResponse.SC_OK);
					response.getWriter().print(json);
				} else { // get item of kind with key
					Long verifiedId;
					try {
						verifiedId = Long.parseLong(id);
					} catch (NumberFormatException e) {
						verifiedId = null;
						sendError(response,
								HttpServletResponse.SC_METHOD_NOT_ALLOWED,
								"Request ID does not exist");
						return;
					}
					BlogPost bp = BlogPostService.getBlogPost(verifiedId);
					if (bp == null) {
						sendError(response,
								HttpServletResponse.SC_METHOD_NOT_ALLOWED,
								"Request ID does not exist");
						return;
					}
					Gson gson = new Gson();
					String json = gson.toJson(bp);
					response.setContentType("application/json; charset=utf-8");
					response.addHeader("Access-Control-Allow-Origin", "*");
					response.addHeader("Cache-Control",
							"max-age=0,no-cache,no-store,post-check=0,pre-check=0");
					response.addHeader("Expires",
							"Mon, 26 Jul 1997 05:00:00 GMT");
					response.setStatus(HttpServletResponse.SC_OK);
					response.getWriter().print(json);
				}
			}
		} catch (Exception e) {
			sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					e.getMessage());
		}
	}

	public void handlePost(String kind, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		if (user != null) {
			if (kind.equalsIgnoreCase(POSTS_KIND)) {
				BlogPost bp = null;
				try {
					if (!request.getContentType().equals(
							"application/x-www-form-urlencoded")) {
						sendError(response, HttpServletResponse.SC_BAD_REQUEST,
								"Bad request parameters");
						return;
					}
					String title = request.getParameter("title");
					String content = request.getParameter("content");
					String meta = request.getParameter("meta");
					bp = new BlogPost(title, content, meta, user.getNickname(),
							new Date(), 1);
				} catch (Exception ex) {
					sendError(response, HttpServletResponse.SC_BAD_REQUEST,
							"Bad request parameters");
					return;
				}
				try {
					BlogPostService.addOrUpdateBlogPost(bp);
				} catch (Exception e) {
					sendError(response,
							HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
							e.getMessage());
					return;
				}
			}
		} else {
			sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Failed to authenticate. Go to http://inkisapi.appspot.com and log in first");
			return;
		}
	}

	public void handlePut(String kind, String id, HttpServletRequest request,
			HttpServletResponse response) throws IOException, ServletException {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		if (user != null) {
			if (kind.equalsIgnoreCase(POSTS_KIND)) {
				Long verifiedId;
				try {
					verifiedId = Long.parseLong(id);
				} catch (NumberFormatException e) {
					verifiedId = null;
					sendError(response,
							HttpServletResponse.SC_METHOD_NOT_ALLOWED,
							"Request ID does not exist");
					return;
				}
				BlogPost bp = BlogPostService.getBlogPost(verifiedId);
				if (bp == null) {
					sendError(response,
							HttpServletResponse.SC_METHOD_NOT_ALLOWED,
							"Request item does not exist");
					return;
				}
				try {
					if (!request.getContentType().equals(
							"application/x-www-form-urlencoded")) {
						sendError(response, HttpServletResponse.SC_BAD_REQUEST,
								"Bad request parameters");
						return;
					}
					String title = request.getParameter("title");
					String date = request.getParameter("date");
					String content = request.getParameter("content");
					String meta = request.getParameter("meta");
					String status = request.getParameter("status");
					if (status != null) {
						bp.setStatus(Integer.parseInt(status));
					}
					if (title != null) {
						bp.setTitle(title);
					}
					if (date != null) {
						Date parsed = new Date();
						SimpleDateFormat format = new SimpleDateFormat(
								"EEE MMM dd HH:mm:ss zzz yyyy");
						parsed = format.parse(date);
						bp.setDate(parsed);
					}
					if (meta != null) {
						bp.setMeta(meta);
					}
					if (content != null) {
						bp.setContent(content);
					}
				} catch (Exception ex) {
					sendError(response, HttpServletResponse.SC_BAD_REQUEST,
							ex.getMessage());
					return;
				}
				try {
					BlogPostService.addOrUpdateBlogPost(bp);
				} catch (Exception e) {
					
					sendError(response,
							HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
							e.getMessage());
					return;
				}
			}
		} else {
			sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Failed to authenticate. Go to http://inkisapi.appspot.com and log in first");
			return;
		}
	}

	public void handleDelete(String kind, String id,
			HttpServletResponse response) throws IOException, ServletException {
		UserService userService = UserServiceFactory.getUserService();
		User user = userService.getCurrentUser();
		if (user != null) {
			try {
				if (kind.equalsIgnoreCase(POSTS_KIND)) {
					Long verifiedId;
					try {
						verifiedId = Long.parseLong(id);
					} catch (NumberFormatException e) {
						verifiedId = null;
						sendError(response,
								HttpServletResponse.SC_METHOD_NOT_ALLOWED,
								"Request ID does not exist");
						return;
					}
					BlogPostService.deleteBlogPost(verifiedId);
				}
			} catch (Exception e) {
				sendError(response,
						HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
						e.getMessage());
			}
		} else {
			sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
					"Failed to authenticate. Go to http://inkisapi.appspot.com and log in first");
			return;
		}
	}

	private void sendError(HttpServletResponse response, int code, String msg)
			throws IOException {
		StringBuilder sb = new StringBuilder();
		sb.append("{\"error\":{");
		sb.append("\"code\":\"" + code + "\",");
		sb.append("\"message\":\"" + msg + "\"}");
		sb.append("}");
		response.setContentType("application/json; charset=utf-8");
		response.addHeader("Access-Control-Allow-Origin", "*");
		response.addHeader("Cache-Control",
				"max-age=0,no-cache,no-store,post-check=0,pre-check=0");
		response.addHeader("Expires", "Mon, 26 Jul 1997 05:00:00 GMT");
		response.setStatus(code);
		response.getWriter().print(sb.toString());
	}
}
